package org.softmed.rest.server.xstream;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.softmed.persistence.PersistenceManager;
import org.softmed.reflection.utils.FieldInfo;
import org.softmed.reflection.utils.ReflectionUtil;
import org.softmed.rest.generation.fields.FieldNameList;
import org.softmed.rest.generation.fields.GenerationConfig;

import com.thoughtworks.xstream.XStream;

public class UnmarshallConfigurator {
	public ReflectionUtil util = new ReflectionUtil();
	public List<Class> compiledClasses = new ArrayList<Class>();;
	// public Class type;
	// public XStream streamer;
	public GenerationConfig genCfg;

	// public Collection<FieldInfo> genFields;

	public void setupXMLStreamer(PersistenceManager odbUtil, Class type,
			XStream streamer, GenerationConfig genCfg) throws Throwable {
		this.genCfg = genCfg;
		compiledClasses.clear();
		setupExpectedXML(odbUtil, type, streamer);
	}

	protected void setupExpectedXML(PersistenceManager odbUtil, Class type,
			XStream streamer) throws Throwable {

		if (type == null || type == Object.class
				|| type == groovy.lang.MetaClass.class)
			return;

		if (compiledClasses.contains(type))
			return;

		compiledClasses.add(type);

		if (genCfg.getAlias(type) != null)
			streamer.alias(genCfg.getAlias(type), type);
		else {
			String name = util.getHifenizedName(type.getSimpleName());
			streamer.alias(name, type);
		}

		FieldNameList attributeFields = genCfg.getAttributeFields(type);
		List<String> attributes = null;
		if (attributeFields != null)
			attributes = attributeFields.getFieldNames();

		FieldNameList omitedFields = genCfg.getOmitedFields(type);
		List<String> omited = null;
		if (omitedFields != null)
			omited = omitedFields.getFieldNames();

		FieldInfo pkinfo = odbUtil.getPrimaryKeyInfo(type);
		if (pkinfo != null)
			streamer.useAttributeFor(pkinfo.getDeclaringClass(), pkinfo
					.getName());

		Collection<FieldInfo> genFields = odbUtil.getGeneratedFields(type);

		// hide list items and other fields
		Class fieldType = null;
		ReflectionUtil util = new ReflectionUtil();
		List<FieldInfo> fields;

		try {

			List<String> nonDisclosedFields = util
					.getNonDeclaredFieldNames(type);
			for (String fieldName : nonDisclosedFields) {
				streamer.omitField(type, fieldName);
			}

			fields = util.getDeclaredFieldInfos(type);
			for (FieldInfo fieldInfo : fields) {

				
				if(fieldInfo.getName().equalsIgnoreCase("metaClass"))
					return;
				
				if (omitedFields != null
						&& omitedFields.getFieldNames().contains(
								fieldInfo.getName())) {
					streamer.omitField(type, fieldInfo.getName());
					continue;
				}

				if (pkinfo != null)
					if (pkinfo.getName().equals(fieldInfo.getName())) {
						streamer.omitField(type, fieldInfo.getName());
						continue;
					}

				if (isFieldGenerated(fieldInfo, genFields)) {
					streamer.omitField(type, fieldInfo.getName());
					continue;
				}

				String alias = genCfg.getFieldAlias(fieldInfo
						.getDeclaringClass(), fieldInfo.getName());
				if (alias == null)
					alias = util.getHifenizedName(fieldInfo.getName());

				if (attributes != null
						&& attributes.contains(fieldInfo.getName())) {
					streamer.useAttributeFor(type, fieldInfo.getName());
//					streamer.aliasAttribute(type, fieldInfo.getName(), alias);
					streamer.aliasField(alias, type, fieldInfo.getName());
				} else
					streamer.aliasField(alias, type, fieldInfo.getName());

				if (util.isPrimitiveOrProxyOrString(fieldInfo.getType()))
					continue;

				if (List.class.isAssignableFrom(fieldInfo.getType())) {
					Class listType = util.isSpecificList(util.getField(type,
							fieldInfo.getName()));
					if (listType != null
							&& !util.isPrimitiveOrProxyOrString(listType))
						setupExpectedXML(odbUtil, listType, streamer);
					else
						streamer.omitField(type, fieldInfo.getName());
				} else
					setupExpectedXML(odbUtil, fieldInfo.getType(), streamer);

			}
		} catch (Throwable e) {
			e.printStackTrace();
		}

		setupExpectedXML(odbUtil, type.getSuperclass(), streamer);

	}

	protected boolean isFieldGenerated(FieldInfo searchedField,
			Collection<FieldInfo> generatedfields) {
		if (generatedfields != null)
			for (FieldInfo fieldInfo : generatedfields) {

				if (fieldInfo.getName().equals(searchedField.getName()))
					return true;
			}

		return false;
	}
}